package org.cjprods.icerupt;

import org.lwjgl.BufferUtils;
import org.lwjgl.system.MathUtil;

import com.hackoeur.jglm.Mat3;
import com.hackoeur.jglm.Mat4;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL21.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL31.*;
import static org.lwjgl.opengl.GL32.*;
import static org.lwjgl.opengl.GL33.*;

import java.io.IOException;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

public final class utils
{
	public static String load_file(String path) throws IOException
	{
		return new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8); 
	}
	
	public static int make_prog(String name) throws IOException
	{
		String vs_src = utils.load_file("shaders/"+name+".vs");
		String fs_src = utils.load_file("shaders/"+name+".fs");
		int prog = glCreateProgram();
		int vs = glCreateShader(GL_VERTEX_SHADER);
		glShaderSource(vs, vs_src);
		glCompileShader(vs);
		glAttachShader(prog, vs);
		
		int fs = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fs, fs_src);
		glCompileShader(fs);
		glAttachShader(prog, fs);
		
		glLinkProgram(prog);
		return prog;
	}
	
	public static int detail__create_texture(int idx)
	{
		glActiveTexture(GL_TEXTURE0 + idx);
		int tex = glGenTextures();
		glBindTexture(GL_TEXTURE_2D, tex);
		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		// no GL_TEXTURE_MIN_FILTER intensionally
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		return tex;
	}

	public static int create_texture(int idx)	// no mipmap
	{
		int tex = detail__create_texture(idx);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		return tex;
	}

	public static int create_texture(int idx, int max_level)	// with mipmap
	{
		int tex = detail__create_texture(idx);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_level);
		return tex;
	}

	public static void texture_resize(int w, int h)
	{
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, w, h, 0, GL_RGBA, GL_FLOAT, 0);
	}
	
	public static int create_framebuffer(int tex)
	{
		int fbo = glGenFramebuffers();
		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
		IntBuffer dbs = BufferUtils.createIntBuffer(1);
		dbs.put(GL_COLOR_ATTACHMENT0);
		dbs.flip();
		glDrawBuffers(dbs);
		return fbo;
	}
	
	public static Mat3 reduce_dimension(Mat4 x)
	{
		FloatBuffer fb = x.getBuffer();
		float[] m = new float[16]; 
		fb.get(m);
		fb.flip();
		return new Mat3(m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]);//FIXME
	}
	
	
	public static float clamp(float x, float a, float b)
	{
		if (x <= a) return a;
		if (x >= b) return b;
		return x;
	}
}
